package server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Hashtable;

import entry.Entry;
import event.Event;
import event.EventHandler;

public class PeerHandler implements Runnable {

	private final Socket mSocket;

	private DataOutputStream mDos;
	private DataInputStream mDis;

	private final EventManager<Event, EventHandler> mEventManager;

	private File mDefaultDirectory;

	public PeerHandler(Socket clientSocket,
			EventManager<Event, EventHandler> eventManager) throws IOException {
		mSocket = clientSocket;

		mEventManager = eventManager;

		// Set the current working directory.
		mDefaultDirectory = new File("");

		mDis = new DataInputStream(mSocket.getInputStream());
		mDos = new DataOutputStream(mSocket.getOutputStream());
	}

	/*
	 * Handle the client requests.
	 */
	@Override
	public void run() {
		System.out.println("> handling peer "
				+ mSocket.getInetAddress().getHostAddress());

		try {
			Event e = null;
			byte[] buffer = null;

			String parameters;
			int request, len;
			long packageOffset, packageSize;

			while (mSocket.isConnected()) {
				// ------------------------------------------
				// This is the protocol for every message:
				// ------------------------------------------
				// (int) EVENT_TYPE
				// (long) OFFSET (offset of segment in TOTAL_LENGTH)
				// (long) TOTAL_LENGTH (total message length)
				// (int) SEGMENT_LENGTH (<= TOTAL_LENGTH)
				// (UTF) PARAMETER
				// (byte[]) BUFFER (of size SEGMENT_LENGTH)
				// ------------------------------------------

				request = mDis.readInt();
				packageOffset = mDis.readLong();
				packageSize = mDis.readLong();
				len = mDis.readInt();
				parameters = mDis.readUTF();

				if (len > 0) {
					buffer = new byte[len];
					mDis.readFully(buffer, 0, len);

					e = new Event(request, parameters, buffer, packageOffset,
							packageSize, mDos);
				} else {
					e = new Event(request, parameters, null, packageOffset,
							packageSize, mDos);
				}

				mEventManager.put(e);
			}
		} catch (IOException e) {
			String ip = mSocket.getInetAddress().getHostAddress();
			System.out.print("Client disconnected: " + ip);

			Model model = Model.getInstance();

			Hashtable<String, Entry> items = model.items;
			Enumeration<Entry> list = items.elements();

			Entry item;
			while (list.hasMoreElements()) {
				item = list.nextElement();
				if (ip.equals(item.key)) {
					String value = item.value;
					int index = value.lastIndexOf('/');
					if (index < 0) {
						index = value.lastIndexOf('\\');
					}
					int len = value.length();

					String key;
					if (index >= 0) {
						if (index >= len - 1) {
							// We don't want to accept files with the file
							// separator as their last character. This will
							// never happen anyways, but just a precaution...
							continue;
						}
						key = value.substring(index + 1);
					} else {
						key = value;
					}
					if (items.remove(key) != null) {
						System.out
								.println("\t> removed: " + ip + " - " + value);
					}
				}
			}
		}
	}

	/*
	 * Server response functions.
	 */

	private boolean server_changeDirectory(String directory) {
		File temp = null;

		if (directory != null) {
			directory = directory.trim(); // trim white space.
			if (directory.length() > 0) {
				if (directory.equals("../") || directory.equals("..")
						|| directory.equals("./") || directory.equals("/.")) {
					// Go back one directory.
					String dirName = "";
					int index = dirName.lastIndexOf('/');
					if (index > 0) {
						dirName = dirName.substring(0, index);
						if (dirName.length() > 0) {
							temp = new File(dirName);
						} else {
							// Return true since, the command is still valid, we
							// just can't
							// go higher up in the hierarchy.
							return true;
						}
					} else if (index == 0) {
						// Go to root folder.
						temp = new File("/");
					}
				} else if (directory.charAt(0) != '/') {
					// If the directory is absolute (starts with /), then just
					// process the string
					// as is.
					String dirName = "/" + directory;
					temp = new File(dirName);
				} else {
					// Otherwise, turn the directory into an absolute directory
					// first.
					temp = new File(directory);
				}

				if (temp != null && temp.exists()) {
					if (temp.isDirectory()) {
						return true;
					}
				}
			}
		}

		return false;
	}

}
